﻿using DAL.Interfases;
using Entidad;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Dapper;
using DapperExtensions;
using Npgsql;
using System.Configuration;
using System.Data;

namespace DAL.Repositories
{
    public interface IRemitoProveedorRepository : IRepository<RemitoProveedor>
    {
        IList<RemitoProveedor> FindAllWithSucursal();
        IList<RemitoProveedor> FindAllLikeNumero(string numero);
        IList<RemitoProveedor> FindAllConProveedorSucursal();
        RemitoProveedor FindByIdConProveedorSucursalDetalle(int id);
        bool EliminarItemDetalle(int id, int orden_id, int producto_id, int sucursal_id, int proveedor_id);
        bool VerificarNumeroRemito(string numero);
        
    }

    public class RemitoProveedorRepository : IRemitoProveedorRepository
    {

        readonly NpgsqlConnection _cnn;

        public RemitoProveedorRepository()
        {
            _cnn = new NpgsqlConnection(ConfigurationManager.ConnectionStrings["RWORLD"].ToString());           
        }

        public IList<RemitoProveedor> FindAll()
        {
            using (IDbConnection _db = new NpgsqlConnection(ConfigurationManager.ConnectionStrings["RWORLD"].ToString()))
            {
                return _db.Query<RemitoProveedor>("SELECT * FROM REMITOPROVEEDOR").ToList();
            }           
        }

        public IQueryable<RemitoProveedor> Find(System.Linq.Expressions.Expression<Func<RemitoProveedor, bool>> predicate)
        {
            throw new NotImplementedException();
        }

        public RemitoProveedor FindById(int id)
        {
            string query = "SELECT * FROM REMITOPROVEEDOR WHERE REMITOPROVEEDOR_ID = " + id;

            using (IDbConnection _db = new NpgsqlConnection(ConfigurationManager.ConnectionStrings["RWORLD"].ToString()))
            {
                return _db.Query<RemitoProveedor>(query).SingleOrDefault();
            }
        }

        public int add(RemitoProveedor newEntity)
        {
            string query = "INSERT INTO " +
                            "REMITOPROVEEDOR (remitoproveedor_numero, remitoproveedor_fecha, " +
                            "remitoproveedor_fecharecepcion, sucid, proid, estid, observaciones) " +
                            "VALUES (@numero, @fecha, @recepcion, @sucursal, @proveedor, @estado, @observaciones); " + 
                            "SELECT CURRVAL('remitoproveedor_remitoproveedor_id_seq'); ";

            string queryDetalle = "INSERT INTO REMITOPROVEEDORDETALLE (remitoproveedor_id, prdid, cantidad, odcid, sucid) " +
                                "VALUES (@remitoproveedor_id, @producto, @cantidad, @orden, @sucursal)";

            string queryPendiente = "UPDATE ORDENCOMPRAPENDIENTE SET OCDCANTIDAD = OCDCANTIDAD - @cantidad " +
                                    "WHERE OCDID = @detalle_id";

            using (IDbConnection _db = new NpgsqlConnection(ConfigurationManager.ConnectionStrings["RWORLD"].ToString()))
            {
                _db.Open();
                IDbTransaction transaction = _db.BeginTransaction();

                int resultado = _db.Query<int>(query, new 
                { numero = newEntity.numero, 
                    fecha = newEntity.fechaemision, 
                    recepcion = newEntity.fecharecepcion, 
                    sucursal = newEntity.sucursal_id, 
                    proveedor = newEntity.proveedor_id, 
                    estado = 1 ,
                    observaciones = newEntity.observaciones}).Single();

                foreach(RemitoProveedorDetalle row in newEntity.detalle)
                {
                    int resultado_detalle = _db.Query<int>(queryDetalle, new { 
                        remitoproveedor_id = resultado, 
                        producto = row.producto_id, 
                        cantidad = row.cantidad, 
                        orden = row.orden_id,
                        sucursal = row.sucursal_id}).Single();

                    _db.Execute(queryPendiente, new { 
                        cantidad = row.cantidad,
                        detalle_id = resultado_detalle});
                }

                transaction.Commit();
                return resultado;
            }
        }

        public bool remove(int id)
        {
            throw new NotImplementedException();
        }

        public int Modify(RemitoProveedor entity)
        {
            string query = "UPDATE REMITOPROVEEDOR SET REMITOPROVEEDOR_NUMERO = @numero, " +
                "REMITOPROVEEDOR_FECHA = @fecha, REMITOPROVEEDOR_FECHARECEPCION = @fecharecepcion, " +
                "SUCID = @sucursal, PROID = @proveedor, OBSERVACIONES = @observaciones " +
                "WHERE REMITOPROVEEDOR_ID = " + entity.id;

            using (IDbConnection _db = new NpgsqlConnection(ConfigurationManager.ConnectionStrings["RWORLD"].ToString()))
            {
                _db.Open();
                IDbTransaction transaction = _db.BeginTransaction();
                int resultado = _db.Execute(query, new
                {
                    numero = entity.numero,
                    fecha = entity.fechaemision,
                    fecharecepcion = entity.fecharecepcion,
                    sucursal = entity.sucursal_id,
                    proveedor = entity.proveedor_id,
                    observaciones = entity.observaciones
                });

                string queryDetalle = "INSERT INTO REMITOPROVEEDORDETALLE (remitoproveedor_id, prdid, cantidad, odcid, sucid) " +
                               "VALUES (@remitoproveedor_id, @producto, @cantidad, @orden, @sucursal)";

                string queryPendiente = "INSERT INTO ORDENCOMPRAPENDIENTE (ODCID, PRDID, OCDCANTIDAD, " +
                    "OCDIMPORTE, SUCID, PROID, ESPID, OCDID) " + 
                    "VALUES (@orden_id, @producto_id, @cantidad, @importe, @sucursal_id, @proveedor_id, @espid, @detalle_id)";

                //revisar insert a ordencomprapendiente
                foreach (RemitoProveedorDetalle row in entity.detalle)
                {
                    if (string.IsNullOrEmpty(row.id.ToString()))
                    {
                        int resultado_detalle = _db.Query<int>(queryDetalle, new
                        {
                            remitoproveedor_id = resultado,
                            producto = row.producto_id,
                            cantidad = row.cantidad,
                            orden = row.orden_id,
                            sucursal = row.sucursal_id
                        }).Single();

                        _db.Execute(queryPendiente, new
                        {
                            cantidad = row.cantidad,
                            producto_id = row.producto_id,
                            orden_id = row.orden_id,
                            proveedor_id = entity.proveedor_id,
                            sucursal_id = row.sucursal_id,
                            importe = 0,
                            detalle_id = resultado_detalle
                        });
                    }
                }

                transaction.Commit();
                return resultado;
            }
        }

        public IList<RemitoProveedor> FindAllWithSucursal()
        {
            string query = "SELECT * FROM REMITOPROVEEDOR " +
                "INNER JOIN SUCURSAL ON SUCURSAL.SUCID = REMITOPROVEEDOR.SUCID";

            using (IDbConnection _db = new NpgsqlConnection(ConfigurationManager.ConnectionStrings["RWORLD"].ToString()))
            {
                return _db.Query<RemitoProveedor, Sucursal, RemitoProveedor>(query, (remito, sucursal) => { remito.sucursal = sucursal; return remito; }, splitOn:"sucid").ToList();
            }     
        }

        public IList<RemitoProveedor> FindAllLikeNumero(string numero)
        {
            string query = "SELECT * FROM REMITOPROVEEDOR " +
              "INNER JOIN SUCURSAL ON SUCURSAL.SUCID = REMITOPROVEEDOR.SUCID " +
              "WHERE REMITOPROVEEDOR.REMITOPROVEEDOR_NUMERO LIKE '%" + numero + "%'";

            using (IDbConnection _db = new NpgsqlConnection(ConfigurationManager.ConnectionStrings["RWORLD"].ToString()))
            {
                return _db.Query<RemitoProveedor, Sucursal, RemitoProveedor>(query, (remito, sucursal) => { remito.sucursal = sucursal; return remito; }, splitOn: "sucid").ToList();
            }     
        }


        public IList<RemitoProveedor> FindAllConProveedorSucursal()
        {
            string query = "SELECT * FROM REMITOPROVEEDOR " +
                "INNER JOIN PROVEEDOR ON PROVEEDOR.PROID = REMITOPROVEEDOR.PROID " +
                "INNER JOIN SUCURSAL ON SUCURSAL.SUCID = REMITOPROVEEDOR.SUCID " +
                "ORDER BY REMITOPROVEEDOR.REMITOPROVEEDOR_FECHA DESC";

            using (IDbConnection _db = new NpgsqlConnection(ConfigurationManager.ConnectionStrings["RWORLD"].ToString()))
            {
                return _db.Query<RemitoProveedor, Proveedor, Sucursal, RemitoProveedor>(query,
                    (remito, proveedor, sucursal) => { 
                        remito.proveedor = proveedor; 
                        remito.sucursal = sucursal; 
                        return remito; }, splitOn: "proid, sucid").ToList();
            }
        }


        public RemitoProveedor FindByIdConProveedorSucursalDetalle(int id)
        {
            string query = "SELECT * FROM REMITOPROVEEDOR " +
                "INNER JOIN PROVEEDOR ON PROVEEDOR.PROID = REMITOPROVEEDOR.PROID " +
                "INNER JOIN SUCURSAL ON SUCURSAL.SUCID = REMITOPROVEEDOR.SUCID " +
                "WHERE REMITOPROVEEDOR.REMITOPROVEEDOR_ID = " + id;

            RemitoProveedor remitoProveedor = new RemitoProveedor();

            using (IDbConnection _db = new NpgsqlConnection(ConfigurationManager.ConnectionStrings["RWORLD"].ToString()))
            {
                remitoProveedor = _db.Query<RemitoProveedor, Proveedor, Sucursal, RemitoProveedor>(query,
                    (remito, proveedor, sucursal) =>
                    {
                        remito.proveedor = proveedor;
                        remito.sucursal = sucursal;
                        return remito;
                    }, splitOn: "proid, sucid").SingleOrDefault();

                string queryDetalle = "SELECT * FROM REMITOPROVEEDORDETALLE " +
                    "INNER JOIN PRODUCTO ON PRODUCTO.PRDID = REMITOPROVEEDORDETALLE.PRDID " +
                    "INNER JOIN ORDENCOMPRA ON ORDENCOMPRA.ODCID = REMITOPROVEEDORDETALLE.ODCID " +
                    "INNER JOIN SUCURSAL ON SUCURSAL.SUCID = REMITOPROVEEDORDETALLE.SUCID " +
                    "WHERE REMITOPROVEEDOR_ID = " + id;

                remitoProveedor.detalle = _db.Query<RemitoProveedorDetalle, Producto, OrdenCompra, Sucursal, RemitoProveedorDetalle>(queryDetalle,
                    (detalle, producto, orden, sucursal) => {
                        detalle.producto = producto;
                        detalle.orden = orden;
                        detalle.sucursal = sucursal;
                        return detalle;
                    }, splitOn: "prdid, odcid, sucid").ToList();

            }

            return remitoProveedor;
        }


        public bool EliminarItemDetalle(int id, int orden_id, int producto_id, int sucursal_id, int proveedor_id)
        {
            bool res = true;
            string query = "DELETE FROM REMITOPROVEEDORDETALLE WHERE REMITOPROVEEDORDETALLE_ID = " + id;
            string queryPendiente = "DELETE FROM ORDENCOMPRAPENDIENTE WHERE ODCID = @orden AND PRDID = @producto AND SUCID = @sucursal AND PROID = @proveedor";

            using (IDbConnection _db = new NpgsqlConnection(ConfigurationManager.ConnectionStrings["RWORLD"].ToString()))
            {
                int resultado = _db.Execute(query);
                int resultadoPendiente = _db.Execute(queryPendiente);
                if (resultado == 0 || resultadoPendiente == 0)
                    res = false;
            }
            return res;
        }


        public bool VerificarNumeroRemito(string numero)
        {
            bool res;
            using (IDbConnection _db = new NpgsqlConnection(ConfigurationManager.ConnectionStrings["RWORLD"].ToString()))
            {
                string query = "SELECT COUNT(*) FROM REMITOPROVEEDOR WHERE REMITOPROVEEDOR_NUMERO = " + numero;
                int resultado = _db.Query<int>(query).Single();
                if (resultado == 0)           
                    res = false;          
                else             
                    res = true;
            }
            return res;
        }
    }
}
